package com.sip.stream.activity.preview.model;

import android.content.Context;
import android.graphics.SurfaceTexture;
import android.util.Log;
import android.view.TextureView;
import android.widget.RelativeLayout;
import androidx.lifecycle.DefaultLifecycleObserver;

import com.sip.stream.helper.PreviewSurfaceTextureHelper;
import com.sip.stream.media.ZFYCameraParameters;
import com.sip.stream.media.ZFYMediaManager;
import com.sip.stream.utils.zfy.GSNV12OSDDataSource;
import com.sip.stream.utils.zfy.IGSNV12DataSource;
import com.sip.stream.utils.zfy.ZFYCameraCallBack;
import com.sip.stream.utils.zfy.consumer.IGSMediaObserver;
import com.sip.stream.utils.zfy.consumer.ZFYMp4Consumer;
import com.sip.stream.utils.zfy.encoder.IGSAudioEncoder;
import com.sip.stream.utils.zfy.encoder.IGSVideoEncoder;

import io.reactivex.Single;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

public class FrontCameraRecordingViewModel implements DefaultLifecycleObserver {
    private static final String TAG = "FrontCamera";

    private ZFYCameraCallBack cameraCallBack;
    private ZFYCameraParameters cameraParameters;
    private CameraViewModel cameraViewModel;
    private WeakReference<Context> contextWeakReference;
    private RelativeLayout layoutPreview;
    private PreviewSurfaceTextureHelper previewSurfaceTextureHelper;
    private ZFYMp4Consumer videoConsumer;
    private boolean needFrontVideo = false;
    private boolean needFrontStream = false;
    private IGSNV12DataSource videoDataSource = null;
    private IGSMediaObserver<IGSNV12DataSource> videoDataSourceObserver = new IGSMediaObserver() {
        @Override
        public void onStop(Object obj) {
            Log.i(TAG, "videoDataSource onStop");
            videoDataSource = null;
            if (previewSurfaceTextureHelper != null) {
                previewSurfaceTextureHelper.setVideoDataSource(null);
            }
            getCameraViewModel().updateCameraStream(true, ZFYMediaManager.getInstance().isNeedVideoStream(), ZFYMediaManager.getInstance().isNeedRemoteStream());
        }
    };

    public FrontCameraRecordingViewModel(Context context) {
        this.contextWeakReference = new WeakReference<>(context);
    }

    private Context getContext() {
        return this.contextWeakReference.get();
    }

    public void setUpTextureView(RelativeLayout relativeLayout) {
        Log.i(TAG, "setUpTextureView " + relativeLayout);
        this.layoutPreview = relativeLayout;
    }

    public Single<Boolean> resumeCamera() {
        Log.i(TAG, "resumeCamera");
        return setup().doOnError(new Consumer() {
            @Override
            public void accept(Object obj) {
                Throwable th = (Throwable) obj;
                th.printStackTrace();
                Log.e(TAG, " " + th.getMessage());
            }
        }).onErrorReturnItem(Boolean.FALSE);
    }


    private Single<Boolean> setup() {
        this.needFrontVideo = ZFYMediaManager.getInstance().getConfig().isDualRecording();
        boolean isFrontCameraStream = ZFYMediaManager.getInstance().getConfig().isFrontCameraStream();
        this.needFrontStream = isFrontCameraStream;
        if (!this.needFrontVideo && !isFrontCameraStream) {
            return Single.just(Boolean.TRUE);
        }
        if (getCameraViewModel().isOpenedCamera()) {
            Log.i(TAG, "isOpenedCamera");
            return Single.just(Boolean.TRUE);
        }
        return Single.just(Boolean.TRUE).flatMap(new Function() {
            @Override
            public  Object apply(Object obj) {
                return setUpSurface();
            }
        }).flatMap(new Function() {
            @Override
            public  Object apply(Object obj) {
                return getCameraViewModel().setUpCamera();
            }
        }).doOnSuccess(new Consumer() {
            @Override
            public  void accept(Object obj) {
                ZFYCameraParameters zFYCameraParameters = (ZFYCameraParameters) obj;
                FrontCameraRecordingViewModel.this.cameraParameters = zFYCameraParameters;
                FrontCameraRecordingViewModel.this.previewSurfaceTextureHelper.setDefaultBufferSize(zFYCameraParameters.getVideoWidth(), zFYCameraParameters.getVideoHeight());
                FrontCameraRecordingViewModel.this.previewSurfaceTextureHelper.doAfterCameraOpened();
            }
        }).map(new Function() {
            @Override
            public  Object apply(Object obj) {
                getCameraViewModel().updateCameraStream(true, false, false);
                return Boolean.TRUE;
            }
        });
    }


    private Single<Boolean> setUpSurface() {
        if (this.layoutPreview == null) {
            return Single.error(new Exception("no set layout yet"));
        }
        return addTextureView().flatMap(new Function() {
            @Override
            public Object apply(Object obj) {
                TextureView textureView = (TextureView) obj;
                PreviewSurfaceTextureHelper previewSurfaceTextureHelper = new PreviewSurfaceTextureHelper(textureView);
                FrontCameraRecordingViewModel.this.previewSurfaceTextureHelper = previewSurfaceTextureHelper;
                return previewSurfaceTextureHelper.setUpSurface();
            }
        });
    }



    private Single<TextureView> addTextureView() {
        return Single.just(Boolean.TRUE).observeOn(AndroidSchedulers.mainThread()).map(new Function() {
            @Override
            public Object apply(Object obj) {
                RelativeLayout relativeLayout = FrontCameraRecordingViewModel.this.layoutPreview;
                if (relativeLayout == null) {
                    return null;
                }else{
                    TextureView textureView = new TextureView(relativeLayout.getContext());
                    textureView.setLayoutParams(new RelativeLayout.LayoutParams(-1, -1));
                    relativeLayout.addView(textureView);
                    return textureView;
                }
            }
        });
    }


    public Single<Boolean> onPauseAction() {
        if (!this.needFrontVideo) {
            return Single.just(Boolean.TRUE);
        }
        Log.i(TAG, "onPauseAction");
        if (ZFYMediaManager.getInstance().isNeedVideoStream()) {
            getCameraViewModel().updateCameraStream(false, ZFYMediaManager.getInstance().isNeedVideoStream(), ZFYMediaManager.getInstance().isNeedRemoteStream());
            return Single.just(Boolean.TRUE);
        }
        return pauseCameraAndSurface().onErrorReturnItem(Boolean.TRUE);
    }

    private Single<Boolean> pauseCameraAndSurface() {
        return getCameraViewModel().onPauseAction().onErrorReturnItem(Boolean.TRUE).flatMap(new Function() {
            @Override
            public  Object apply(Object obj) {
                return releaseSurface();
            }
        });
    }

    private CameraViewModel getCameraViewModel() {
        if (this.cameraViewModel == null) {
            if (this.cameraCallBack == null) {
                this.cameraCallBack = new ZFYCameraCallBack() {
                    @Override
                    public void onCameraSwitch() {
                    }

                    @Override
                    public void onCaptureComplete(byte[] bArr, int i) {
                    }

                    @Override
                    public void onRemoteStream(byte[] bArr, long j) {
                    }

                    @Override
                    public void onError(String str) {
                        Log.e(TAG, "onError " + str);
                    }

                    @Override
                    public void onVideoStream(byte[] bArr, long j) {
                        if (FrontCameraRecordingViewModel.this.videoDataSource != null) {
                            FrontCameraRecordingViewModel.this.videoDataSource.addNV12Data(bArr, j);
                        }
                    }

                    @Override
                    public SurfaceTexture getPreviewSurfaceTexture() {
                        return FrontCameraRecordingViewModel.this.previewSurfaceTextureHelper.getPreviewSurface();
                    }

                    @Override
                    public void cameraStatusChange(int i) {
                        Log.w(TAG, "cameraStatusChange " + i);
                    }
                };
            }
            CameraViewModel cameraViewModel = new CameraViewModel(getContext(), this.cameraCallBack);
            this.cameraViewModel = cameraViewModel;
            cameraViewModel.setFront(true);
        }
        return this.cameraViewModel;
    }

    private synchronized Single<Boolean> releaseSurface() {
        if (previewSurfaceTextureHelper == null) {
            return Single.just(Boolean.TRUE);
        }
        return previewSurfaceTextureHelper.releaseSurface().onErrorReturnItem(Boolean.TRUE).doOnSuccess(new Consumer() {
            @Override
            public void accept(Object obj) {
                previewSurfaceTextureHelper = null;
            }
        }).observeOn(AndroidSchedulers.mainThread()).map(new Function() {
            @Override
            public Object apply(Object obj) {
                Log.i(TAG, "releaseSurface");
                if (FrontCameraRecordingViewModel.this.layoutPreview == null) {
                    return Boolean.FALSE;
                }
                FrontCameraRecordingViewModel.this.layoutPreview.removeAllViews();
                return Boolean.TRUE;
            }
        });
    }

    public Single<IGSNV12DataSource> createVideoDataSource() {
        if (this.videoDataSource != null) {
            Log.i(TAG, "videoDataSource != null");
            return Single.just(this.videoDataSource);
        }
        return Single.just(Boolean.TRUE).delay(1100L, TimeUnit.MILLISECONDS).map(new Function() {
            @Override
            public Object apply(Object obj) {
                getCameraViewModel().updateCameraStream(true, true, false);
                ZFYCameraParameters cameraParameters = getCameraViewModel().getCameraParameters();
                Log.i(TAG, "createVideoDataSource " + cameraParameters.getVideoWidth() + " x " + cameraParameters.getVideoHeight());
                GSNV12OSDDataSource gSNV12OSDDataSource = new GSNV12OSDDataSource(cameraParameters.getVideoWidth(), cameraParameters.getVideoHeight(), cameraParameters.getVideoFps());
                gSNV12OSDDataSource.addObserver(FrontCameraRecordingViewModel.this.videoDataSourceObserver);
                return gSNV12OSDDataSource;
            }
        }).doOnSuccess(new Consumer() {
            @Override
            public void accept(Object obj) {
                FrontCameraRecordingViewModel.this.videoDataSource = (IGSNV12DataSource) obj;
            }
        });
    }

    public Single<IGSNV12DataSource> createRemoteDataSource() {
        if (this.videoDataSource != null) {
            Log.i(TAG, "videoDataSource != null");
            return Single.just(this.videoDataSource);
        }
        return Single.just(Boolean.TRUE).map(new Function() {
            @Override
            public Object apply(Object obj) {
                getCameraViewModel().updateCameraStream(true, true, false);
                ZFYCameraParameters cameraParameters = getCameraViewModel().getCameraParameters();
                Log.i(TAG, "createVideoDataSource " + cameraParameters.getVideoWidth() + " x " + cameraParameters.getVideoHeight());
                GSNV12OSDDataSource gSNV12OSDDataSource = new GSNV12OSDDataSource(cameraParameters.getVideoWidth(), cameraParameters.getVideoHeight(), cameraParameters.getVideoFps());
                gSNV12OSDDataSource.addObserver(FrontCameraRecordingViewModel.this.videoDataSourceObserver);
                return gSNV12OSDDataSource;
            }
        }).doOnSuccess(new Consumer() {
            @Override
            public void accept(Object obj) {
                FrontCameraRecordingViewModel.this.videoDataSource = (IGSNV12DataSource) obj;
            }
        });
    }


    public Single<Boolean> startVideoAction() {
        if (!this.needFrontVideo) {
            return Single.just(Boolean.TRUE);
        }
        return Single.zip(Single.just(ZFYMediaManager.getInstance().getEncoderManager().getMp4AudioEncoder()), createVideoDataSource().map(new Function() {
            @Override
            public Object apply(Object obj) {

                IGSNV12DataSource iGSNV12DataSource = (IGSNV12DataSource) obj;
                IGSVideoEncoder frontVideoEncoder = ZFYMediaManager.getInstance().getEncoderManager().getFrontVideoEncoder(FrontCameraRecordingViewModel.this.cameraParameters);
                iGSNV12DataSource.addConsumer(frontVideoEncoder);
                return frontVideoEncoder;
            }
        }), new BiFunction() {
            @Override
            public Object apply(Object obj, Object obj2) {
                IGSAudioEncoder iGSAudioEncoder = (IGSAudioEncoder) obj;
                IGSVideoEncoder iGSVideoEncoder = (IGSVideoEncoder) obj2;
                return new ZFYMp4Consumer(iGSVideoEncoder, iGSAudioEncoder);
            }
        }).map(new Function() {
            @Override
            public Object apply(Object obj) {
                FrontCameraRecordingViewModel.this.videoConsumer = (ZFYMp4Consumer) obj;
                return Boolean.TRUE;
            }
        });
    }


    public synchronized Single<Boolean> stopVideoAction() {
        if (!this.needFrontVideo && !this.needFrontStream) {
            return Single.just(Boolean.TRUE);
        }
        return Single.just(Boolean.TRUE).map(new Function() {
            @Override
            public Object apply(Object obj) {
                if (FrontCameraRecordingViewModel.this.videoConsumer != null) {
                    Log.i(TAG, "stopVideoAction mp4Consumer stop");
                    FrontCameraRecordingViewModel.this.videoConsumer.stop();
                } else {
                    Log.i(TAG, "mp4 == null");
                }
                return Boolean.TRUE;
            }
        });
    }
}
